#include "xbigrequest.h"
#include "xsmallrequest.h"
#include "libxsip.h"
#include "msg.h"
#include "xsip.h"

#define MAX(a, b) ((a > b) ? a : b)
#define MIN(a, b) ((a < b) ? a : b)

static DelayInterval convert2DelayInterval(int ts)
{
	time_base_seconds sec = ts / 1000;
	time_base_seconds usec = (ts % 1000) * 1000;
	return DelayInterval(sec, usec);
}

XSIPBigClientTransactionState::XSIPBigClientTransactionState(void* transaction)
{
	m_transaction = (XSIPTransaction*)transaction;
	m_ts = 250;
	if (m_transaction->getTransport()->getObject("XSIPDgramTransport"))
		m_retran = new RetranEntry(this, convert2DelayInterval(m_ts));
	else
		m_retran = NULL;
	m_ts = MIN(m_ts * 2, 2000);
	m_timeout = new TimeoutEntry(this, DelayInterval(15, 0));
	m_ack = -1;
	m_ts = 250;
}

XSIPBigClientTransactionState::~XSIPBigClientTransactionState()
{
	if (m_retran)
		XSIPEngine::getCurrentThreadEngine()->removeEntry(m_retran);
	XSIPEngine::getCurrentThreadEngine()->removeEntry(m_timeout);
	if (m_retran)
		delete m_retran;
	delete m_timeout;
}

int XSIPBigClientTransactionState::touch()
{
	int ret = 0;
	
	if (m_state == TSX_STATE_SEND_REQUEST)
	{
		setState(TSX_STATE_SEND_N_REQUEST);
		ret = touch();
		if (m_retran)
			XSIPEngine::getCurrentThreadEngine()->addEntry(m_retran);
		XSIPEngine::getCurrentThreadEngine()->addEntry(m_timeout);
	}
	else if (m_state == TSX_STATE_SEND_N_REQUEST)
	{
		m_ack = 0;
		XSIPRequest* request = m_transaction->getRequest();
		XSIPRequest* sub = request->subRequest(m_ack);
		XSIPHeader* header = request->getHeader();
		header->addHeader(XSIP_MSG_HEADER_PAYLOAD_OFFSET, XSIPPayloadOffsetHeader::getPayloadOffset(m_ack, sub->getContent()->getSize(), request->getContent()->getSize()));
		XSIPTransport *transport = m_transaction->getTransport();
		ret = transport->sendMessage(sub, m_transaction);
	}
	else if (m_state == TSX_STATE_SEND_REQUEST_AGAIN)
	{
		XSIPRequest* request = m_transaction->getRequest();
		XSIPRequest* sub = request->subRequest(m_ack);
		XSIPTransport *transport = m_transaction->getTransport();
		ret = transport->sendMessage(sub, m_transaction);
		if (m_retran)
			XSIPEngine::getCurrentThreadEngine()->updateEntry(m_retran, convert2DelayInterval(m_ts));
		m_ts = MIN(m_ts * 2, 2000);
	}
	else if (m_state == TSX_STATE_RECV_1_RESPONSE)
	{
		XSIPResponse *response = m_transaction->getResponse();
		XSIPRequest *request = m_transaction->getRequest();
		XSIPPayloadOffsetAckHeader ack(response->getHeader()->getHeader(XSIP_MSG_HEADER_PAYLOAD_OFFSET_ACK));
		if ((ack.getAck()+1) == request->getRequestCount())
		{
			XSIPCommand* command = (XSIPCommand*) m_transaction->getOwner()->getObject("XSIPCommand");
			XSIPDataReceiver *receiver = command->getDataReceiver();
			receiver->onResponse(m_transaction, response);
			receiver->onDataRead(m_transaction, response->getContent()->getData(), response->getContent()->getSize());
			receiver->onComplete(m_transaction, 0, response);
			complete();
		}
		else if (m_ack <= ack.getAck())
		{
			m_ack = ack.getAck() + 1;
			XSIPRequest* request = m_transaction->getRequest();
			XSIPRequest* sub = request->subRequest(m_ack);
			XSIPHeader* header = request->getHeader();
			header->addHeader(XSIP_MSG_HEADER_PAYLOAD_OFFSET, XSIPPayloadOffsetHeader::getPayloadOffset(m_ack, sub->getContent()->getSize(), request->getContent()->getSize()));
			XSIPTransport *transport = m_transaction->getTransport();
			ret = transport->sendMessage(sub, m_transaction);
		}
	}
	else if (m_state == TSX_STATE_TIMEOUT)
	{
		m_transaction->onEvent(m_transaction, XSIP_EVENT_CODE_TIMEOUT);
		if (m_retran)
			XSIPEngine::getCurrentThreadEngine()->removeEntry(m_retran);
	}
	return ret;
}

void XSIPBigClientTransactionState::complete()
{
	m_transaction->onEvent(m_transaction, XSIP_EVENT_CODE_SUCCESS);
	if (m_retran)
		XSIPEngine::getCurrentThreadEngine()->removeEntry(m_retran);
	XSIPEngine::getCurrentThreadEngine()->removeEntry(m_timeout);
}

void XSIPBigClientTransactionState::timeout()
{
	setState(TSX_STATE_TIMEOUT);
	touch();
}

XSIPBigServerTransactionState::XSIPBigServerTransactionState()
{
	m_retran = NULL;
	m_timeout = new TimeoutEntry(this, DelayInterval(15, 0));
	m_contentIndex = -1;
	m_ts = 250;
}

XSIPBigServerTransactionState::~XSIPBigServerTransactionState()
{
	XSIPEngine::getCurrentThreadEngine()->removeEntry(m_timeout);
	delete m_timeout;
}

int XSIPBigServerTransactionState::touch()
{
	int ret = 0;
	if (m_state == TSX_STATE_RECV_N_REQUEST)
	{
		XSIPRequest *request = m_transaction->getRequest();
		XSIPPayloadOffsetHeader payload(request->getHeader()->getHeader(XSIP_MSG_HEADER_PAYLOAD_OFFSET));
		if ((payload.getContentIndex()+1) == request->getRequestCount())
		{
			m_contentIndex = payload.getContentIndex();
			XSIPCommand* command = (XSIPCommand*)m_transaction->getOwner()->getObject("XSIPCommand");
			XSIPResponse *response = m_transaction->getResponse();
			response->getHeader()->addHeader(XSIP_MSG_HEADER_PAYLOAD_OFFSET_ACK, m_contentIndex);
			XSIPEngine::getCurrentThreadEngine()->onCommand(command, m_transaction, request);
		}
		else if (m_contentIndex < payload.getContentIndex())
		{
			m_contentIndex = payload.getContentIndex();
			XSIPCall* command = (XSIPCall*)m_transaction->getOwner();
			if (!command)
			{
				command = XSIPEngine::getCurrentThreadEngine()->onRequestHook(m_transaction, request);
				m_transaction->setOwner((XSIPCall*) command->getObject("XSIPCall"));
			}
			XSIPResponse* response = command->createResponse(m_transaction, request, 200);
			response->getHeader()->addHeader(XSIP_MSG_HEADER_PAYLOAD_OFFSET_ACK, m_contentIndex);
			XSIPTransport *transport = m_transaction->getTransport();
			ret = transport->sendMessage(response, m_transaction);
			XSIPDataReceiver* receiver = command->getDataReceiver();
			if (m_contentIndex == 0)
			{
				XSIPEngine::getCurrentThreadEngine()->addEntry(m_timeout);
			}
		}
		
	}
	else if (m_state == TSX_STATE_SEND_RESPONSE)
	{
		XSIPResponse* response = m_transaction->getResponse();
		XSIPTransport* transport = m_transaction->getTransport();
		XSIPHeader *header = response->getHeader();
		//header->clearHeader(XSIP_MSG_HEADER_PAYLOAD_OFFSET_ACK);
		ret = transport->sendMessage(response, m_transaction);
	}
	else if (m_state == TSX_STATE_TIMEOUT)
	{
		m_transaction->onEvent(m_transaction, XSIP_EVENT_CODE_TIMEOUT);
		XSIPEngine::getCurrentThreadEngine()->removeEntry(m_retran);
	}
	return ret;
}

void XSIPBigServerTransactionState::complete()
{

}

void XSIPBigServerTransactionState::timeout()
{
	m_transaction->onEvent(m_transaction, XSIP_EVENT_CODE_SUCCESS);
	XSIPEngine::getCurrentThreadEngine()->removeEntry(m_timeout);
}